-
-
Notifications
You must be signed in to change notification settings - Fork 189
fix(rsc): propagate client reference invalidation to server #788
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(rsc): propagate client reference invalidation to server #788
Conversation
e010a1f
to
da11904
Compare
commit: |
// intercept client hmr to propagate client boundary invalidation to server environment | ||
const oldSend = server.environments.client.hot.send | ||
server.environments.client.hot.send = async function ( | ||
this, | ||
...args: any[] | ||
) { | ||
const e = args[0] as vite.UpdatePayload | ||
if (e && typeof e === 'object' && e.type === 'update') { | ||
for (const update of e.updates) { | ||
if (update.type === 'js-update') { | ||
const mod = | ||
server.environments.client.moduleGraph.urlToModuleMap.get( | ||
update.path, | ||
) | ||
if (mod && mod.id && manager.clientReferenceMetaMap[mod.id]) { | ||
const serverMod = | ||
server.environments.rsc!.moduleGraph.getModuleById(mod.id) | ||
if (serverMod) { | ||
server.environments.rsc!.moduleGraph.invalidateModule( | ||
serverMod, | ||
) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
return oldSend.apply(this, args as any) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this only covers the case where client boundary gets hmr-ed, technically there are edge cases like client reference itself doesn't self-accept or invalidateModule
is directly used, so they causes full-reload instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However, patching invalidateModule
directly will break the first test case "non-client-reference client hmr" as this is more aggressive invalidation.
const oldInvalidateModule = server.environments.client.moduleGraph.invalidateModule
server.environments.client.moduleGraph.invalidateModule = function (this, ...args) {
const mod = args[0];
if (mod && mod.id && manager.clientReferenceMetaMap[mod.id]) {
const serverMod =
server.environments.rsc!.moduleGraph.getModuleById(mod.id)
if (serverMod) {
server.environments.rsc!.moduleGraph.invalidateModule(
serverMod,
)
}
}
return oldInvalidateModule.apply(this, args);
}
I think this still has an issue when
Here changing However, upon refresh, it will probably end up with:
|
Description
Reproduction
hmr-client-dep2/client-dep.ts
This is because when
client-dep.ts
is modified, it invalidatesclient.tsx
(on client environment) for hmr, which becomes a new module fetched asclient.tsx?t=xxx
, butclient.tsx
on server environment (which exists as "proxy module" withregisterClientReference
) is not invalidated. When re-rendering RSC, server payload includes a client component with old module referenceclient.tsx
instead of newclient.tsx?t=xxx
, which has a different identity asTestHmrClientDep2
functional component and thus React re-mounts node.Screencast.From.2025-08-27.16-06-40.mp4
TODO
moduleGraph.invalidateModule
from client environment to rsc environment.